package org.jlambda;

import static org.jlambda.util.Lists.last;
import static org.jlambda.util.Lists.seq;
import static org.jlambda.util.Lists.tail;
import static org.jlambda.util.Lists.zipWith;

import org.jlambda.functions.Fun2;
import org.jlambda.list.List;
import org.jlambda.list.MemoizingList;
import org.jlambda.listFunctions.ListFun1;
import org.jlambda.util.Lists;
import org.jlambda.util.Math;

public class Fib extends ListFun1<Boolean, Number> {

	boolean usezip = false;
	Fun2<Number, Number, Number> addints = Math.add; 
		
	MemoizingList<Number> list;
	
	public Number getNext() {
		Iterable itra = new Lists.CalculatedIterableProxy(list);
		// zipWith (+) fibs (tail fibs)
		// evaluates whole list each time
		if (usezip) {
			return last( (MemoizingList<Number>)seq(
					zipWith(addints, itra, 
							tail(itra))
							) )
					;
		} 
		
		Number a = (Number) last( list, 2).toArray()[0];
		Number b = last(list); 
		
		// lazy but only adds the last to the second last when needed
		return addints.apply( a, b);
	}

	@Override
	protected void create(List<Number> list, Boolean p1) {
		this.usezip = p1;
		this.list = (MemoizingList<Number>) list;
		this.list.append(0.0);
		this.list.append(1.0);
	}

}
